]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Add UnlockDialog for unlocking the screen shield
authorGiovanni Campagna <gcampagna@src.gnome.org>
Sun, 20 May 2012 16:30:14 +0000 (18:30 +0200)
committerGiovanni Campagna <gcampagna@src.gnome.org>
Sat, 21 Jul 2012 13:40:28 +0000 (15:40 +0200)
When the screenshield is deactivated, instead of going back to the
session immediately, prompt the user for authentication.
This essentially reinstates what used to be provided by gnome-screensaver.

https://bugzilla.gnome.org/show_bug.cgi?id=619955

data/theme/gdm.css [deleted file]
data/theme/gnome-shell.css
js/Makefile.am
js/ui/screenShield.js
js/ui/sessionMode.js
js/ui/unlockDialog.js [new file with mode: 0644]

diff --git a/data/theme/gdm.css b/data/theme/gdm.css
deleted file mode 100644 (file)
index daaa575..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* Copyright 2011, Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU Lesser General Public License,
- * version 2.1, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
- * more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/* Login Dialog */
-
-.login-dialog-banner {
-    font-size: 10pt;
-    font-weight: bold;
-    text-align: center;
-    color: #666666;
-    padding-bottom: 1em;
-}
-
-.login-dialog-title {
-    font-size: 14pt;
-    font-weight: bold;
-    color: #666666;
-    padding-bottom: 2em;
-}
-
-.login-dialog {
-    border-radius: 16px;
-    min-height: 150px;
-    max-height: 700px;
-    min-width: 350px;
-}
-
-.login-dialog-prompt-fingerprint-message {
-    font-size: 10.5pt;
-}
-
-.login-dialog-user-list-view {
-    -st-vfade-offset: 1em;
-}
-
-.login-dialog-user-list {
-    spacing: 12px;
-}
-
-.login-dialog-user-list-item {
-    color: #666666;
-}
-
-.login-dialog-user-list-item:ltr {
-    padding-right: 1em;
-}
-
-.login-dialog-user-list-item:rtl {
-    padding-left: 1em;
-}
-
-.login-dialog-user-list-item .login-dialog-user-list-item-name {
-    font-size: 20pt;
-    padding-left: 1em;
-    color: #666666;
-}
-
-.login-dialog-user-list-item:hover .login-dialog-user-list-item-name {
-    color: white;
-}
-
-.login-dialog-user-list-item:focus .login-dialog-user-list-item-name {
-    color: white;
-    text-shadow: black 0px 2px 2px;
-}
-
-.login-dialog-user-list-item-vertical-layout {
-    spacing: 2px;
-}
-
-.login-dialog-user-list-item .login-dialog-user-list-item-focus-bin {
-    background-color: rgba(0,0,0,0.0);
-    height: 2px;
-}
-
-.login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin {
-    background-color: #666666;
-}
-
-.login-dialog-user-list-item-icon {
-    border: 2px solid #8b8b8b;
-    border-radius: 8px;
-    width: 64px;
-    height: 64px;
-}
-
-.login-dialog-not-listed-button {
-    padding-top: 2em;
-}
-.login-dialog-not-listed-label {
-    font-size: 14pt;
-    font-weight: bold;
-    color: #666666;
-}
-
-.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
-    color: white;
-}
-
-.login-dialog-prompt-layout {
-    padding-bottom: 32px;
-}
-.login-dialog-prompt-label {
-    color: white;
-    font-size: 20pt;
-}
-
-.login-dialog-prompt-entry {
-    padding: 4px;
-    border-radius: 4px;
-    border: 2px solid #5656cc;
-    color: black;
-    background-color: white;
-    caret-color: black;
-    caret-size: 1px;
-    width: 15em;
-}
-
-.login-dialog-prompt-entry .capslock-warning {
-    icon-size: 16px;
-    warning-color: #999;
-}
-
-.login-dialog-prompt-entry:insensitive {
-    color: rgba(0,0,0,0.7);
-    border: 2px solid #565656;
-}
-
-.login-dialog-session-list {
-    color: #ffffff;
-    font-size: 10.5pt;
-}
-
-.login-dialog-session-list-button {
-    padding: 4px;
-}
-
-.login-dialog-session-list-button:focus {
-    background-color: #4c4c4c;
-}
-
-.login-dialog-session-list-button:active {
-    background-color: #4c4c4c;
-}
-
-.login-dialog-session-list-button:hover {
-    font-weight: bold;
-}
-
-.login-dialog-session-list-scroll-view {
-    background-gradient-start: rgba(80,80,80,0.3);
-    background-gradient-end: rgba(80,80,80,0.7);
-    background-gradient-direction: vertical;
-    box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
-    border-radius: 8px;
-    border: 1px solid rgba(80,80,80,1.0);
-    padding: .5em;
-}
-
-.login-dialog-session-list-item:focus {
-    background-color: #666666;
-}
-
-.login-dialog-session-list-triangle {
-    padding-right: .5em;
-}
-
-.login-dialog-session-list-item-box {
-    spacing: .25em;
-}
-
-.login-dialog-session-list-item-dot {
-    width: .75em;
-    height: .75em;
-}
index b3dcb821e0b079a9eb1f640a78e2189c6653446d..5881172589b30c878158dfacc6753197cf144086 100644 (file)
@@ -2008,3 +2008,189 @@ StScrollBar StButton#vhandle:hover
     border-radius: 4px;
     background-color: rgba(255,255,255,0.33);
 }
+
+/* Login Dialog */
+
+.login-dialog-banner {
+    font-size: 10pt;
+    font-weight: bold;
+    text-align: center;
+    color: #666666;
+    padding-bottom: 1em;
+}
+
+.login-dialog-title {
+    font-size: 14pt;
+    font-weight: bold;
+    color: #666666;
+    padding-bottom: 2em;
+}
+
+.login-dialog {
+    border-radius: 16px;
+    min-height: 150px;
+    max-height: 700px;
+    min-width: 350px;
+}
+
+.login-dialog-prompt-fingerprint-message {
+    font-size: 10.5pt;
+}
+
+.login-dialog-user-list-view {
+    -st-vfade-offset: 1em;
+}
+
+.login-dialog-user-list {
+    spacing: 12px;
+}
+
+.login-dialog-user-list-item {
+    color: #666666;
+}
+
+.login-dialog-user-list-item:ltr {
+    padding-right: 1em;
+}
+
+.login-dialog-user-list-item:rtl {
+    padding-left: 1em;
+}
+
+.login-dialog-user-list-item .login-dialog-user-list-item-name {
+    font-size: 20pt;
+    padding-left: 1em;
+    color: #666666;
+}
+
+.login-dialog-user-list-item:hover .login-dialog-user-list-item-name {
+    color: white;
+}
+
+.login-dialog-user-list-item:focus .login-dialog-user-list-item-name {
+    color: white;
+    text-shadow: black 0px 2px 2px;
+}
+
+.login-dialog-user-list-item-vertical-layout {
+    spacing: 2px;
+}
+
+.login-dialog-user-list-item .login-dialog-user-list-item-focus-bin {
+    background-color: rgba(0,0,0,0.0);
+    height: 2px;
+}
+
+.login-dialog-user-list-item:focus .login-dialog-user-list-item-focus-bin {
+    background-color: #666666;
+}
+
+.login-dialog-user-list-item-icon {
+    border: 2px solid #8b8b8b;
+    border-radius: 8px;
+    width: 64px;
+    height: 64px;
+}
+
+.login-dialog-not-listed-label {
+    font-size: 14pt;
+    font-weight: bold;
+    color: #666666;
+}
+
+.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
+    color: #E8E8E8;
+}
+
+.login-dialog-prompt-layout {
+    padding-bottom: 32px;
+}
+.login-dialog-prompt-label {
+    color: white;
+    font-size: 20pt;
+}
+
+.login-dialog-prompt-entry {
+    padding: 4px;
+    border-radius: 4px;
+    border: 2px solid #5656cc;
+    color: black;
+    background-color: white;
+    caret-color: black;
+    caret-size: 1px;
+    width: 15em;
+}
+
+.login-dialog-prompt-entry .capslock-warning {
+    icon-size: 16px;
+    warning-color: #999;
+}
+
+.login-dialog-prompt-entry:insensitive {
+    color: rgba(0,0,0,0.7);
+    border: 2px solid #565656;
+}
+
+.login-dialog-session-list {
+    color: #ffffff;
+    font-size: 10.5pt;
+}
+
+.login-dialog-session-list-button {
+    padding: 4px;
+}
+
+.login-dialog-session-list-button:focus {
+    background-color: #4c4c4c;
+}
+
+.login-dialog-session-list-button:active {
+    background-color: #4c4c4c;
+}
+
+.login-dialog-session-list-button:hover {
+    font-weight: bold;
+}
+
+.login-dialog-session-list-scroll-view {
+    background-gradient-start: rgba(80,80,80,0.3);
+    background-gradient-end: rgba(80,80,80,0.7);
+    background-gradient-direction: vertical;
+    box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
+    border-radius: 8px;
+    border: 1px solid rgba(80,80,80,1.0);
+    padding: .5em;
+}
+
+.login-dialog-session-list-item:focus {
+    background-color: #666666;
+}
+
+.login-dialog-session-list-triangle {
+    padding-right: .5em;
+}
+
+.login-dialog-session-list-item-box {
+    spacing: .25em;
+}
+
+.login-dialog-session-list-item-dot {
+    width: .75em;
+    height: .75em;
+}
+
+.unlock-dialog-user-name {
+    padding: 4px;
+    border-radius: 4px;
+    border: 2px solid #5656cc;
+    color: black;
+    background-color: white;
+    caret-color: black;
+    caret-size: 1px;
+    width: 15em;
+    text-align: right;
+}
+
+.unlock-dialog-user-name-container {
+    spacing: .4em;
+}
index cd4136b3b03a2ad5445313ba02930dc30ec429f3..cf2353c81f52dc57293041fff8941c8ab31a9c56 100644 (file)
@@ -91,6 +91,7 @@ nobase_dist_js_DATA =         \
        ui/status/bluetooth.js  \
        ui/telepathyClient.js   \
        ui/tweener.js           \
+       ui/unlockDialog.js      \
        ui/userMenu.js          \
        ui/viewSelector.js      \
        ui/wanda.js             \
index 1b963e302d8bbe0bbfb7991c9fec213df2e7bd9d..b83debbfa7714692ff924656486b11e62e120399 100644 (file)
@@ -8,7 +8,7 @@ const St = imports.gi.St;
 
 const GnomeSession = imports.misc.gnomeSession;
 const Lightbox = imports.ui.lightbox;
-const LoginDialog = imports.gdm.loginDialog;
+const UnlockDialog = imports.ui.unlockDialog;
 const Main = imports.ui.main;
 
 const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
@@ -48,8 +48,7 @@ const ScreenShield = new Lang.Class({
         let constraint = new Clutter.BindConstraint({ source: global.stage,
                                                       coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
         this._group.add_constraint(constraint);
-        this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
-        this._group.connect('button-press-event', Lang.bind(this, this._onButtonPressEvent));
+
         this._lightbox = new Lightbox.Lightbox(this._group,
                                                { inhibitEvents: true, fadeInTime: 10, fadeFactor: 1 });
         this._background = Meta.BackgroundActor.new_for_screen(global.screen);
@@ -71,6 +70,8 @@ const ScreenShield = new Lang.Class({
             if (lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY)) {
                 this._background.show();
                 this._background.raise_top();
+
+                this._showUnlockDialog();
             } else {
                 this._popModal();
             }
@@ -84,13 +85,32 @@ const ScreenShield = new Lang.Class({
         this._background.hide();
     },
 
-    _onKeyPressEvent: function(object, keyPressEvent) {
-        log("in _onKeyPressEvent - lock is enabled: " + this._settings.get_boolean(LOCK_ENABLED_KEY));
-        this._popModal();
+    _showUnlockDialog: function() {
+        if (this._dialog)
+            return;
+
+        this._dialog = new UnlockDialog.UnlockDialog();
+        this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
+        this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
+
+        this._dialog.open(global.get_current_time());
     },
 
-    _onButtonPressEvent: function(object, buttonPressEvent) {
-        log("in _onButtonPressEvent - lock is enabled: " + this._settings.get_boolean(LOCK_ENABLED_KEY));
+    _onUnlockFailed: function() {
+        // for now, on failure we just destroy the dialog and create a new
+        // one (this is what gnome-screensaver does)
+        // in the future, we may want to go back to the lock screen instead
+
+        this._dialog.destroy();
+        this._dialog = null;
+
+        this._showUnlockDialog();
+    },
+
+    _onUnlockSucceded: function() {
+        this._dialog.destroy();
+        this._dialog = null;
+
         this._popModal();
     },
 });
index 8c259302b10a06d383bf64038620ceaa96c21464..dff6c84221ed79eb4ffded0e00771051f8e01575 100644 (file)
@@ -39,7 +39,7 @@ const _modes = {
              hasRunDialog: false,
              hasWorkspaces: false,
              createSession: Main.createGDMSession,
-             extraStylesheet: global.datadir + '/theme/gdm.css',
+             extraStylesheet: null,
              statusArea: {
                  order: [
                      'a11y', 'display', 'keyboard',
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
new file mode 100644 (file)
index 0000000..4a849c7
--- /dev/null
@@ -0,0 +1,221 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const AccountsService = imports.gi.AccountsService;
+const Clutter = imports.gi.Clutter;
+const Gdm = imports.gi.Gdm;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Signals = imports.signals;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
+
+const Main = imports.ui.main;
+const ModalDialog = imports.ui.modalDialog;
+const ShellEntry = imports.ui.shellEntry;
+const Tweener = imports.ui.tweener;
+const UserMenu = imports.ui.userMenu;
+
+const Batch = imports.gdm.batch;
+const GdmUtil = imports.gdm.util;
+
+// A widget showing the user avatar and name
+const UserWidget = new Lang.Class({
+    Name: 'UserWidget',
+
+    _init: function(user) {
+        this._user = user;
+
+        this.actor = new St.BoxLayout({ style_class: 'unlock-dialog-user-name-container',
+                                        vertical: false });
+
+        this._avatar = new UserMenu.UserAvatarWidget(user);
+        this.actor.add(this._avatar.actor,
+                       { x_fill: true, y_fill: true });
+
+        this._label = new St.Label({ style_class: 'unlock-dialog-user-name' });
+        this.actor.add(this._label,
+                       { expand: true,
+                         x_fill: true,
+                         y_fill: true });
+
+        this._userLoadedId = this._user.connect('notify::is-loaded',
+                                                Lang.bind(this, this._updateUser));
+        this._userChangedId = this._user.connect('changed',
+                                                 Lang.bind(this, this._updateUser));
+        if (this._user.is_loaded)
+            this._updateUser();
+    },
+
+    destroy: function() {
+        if (this._userLoadedId != 0) {
+            this._user.disconnect(this._userLoadedId);
+            this._userLoadedId = 0;
+        }
+
+        if (this._userChangedId != 0) {
+            this._user.disconnect(this._userChangedId);
+            this._userChangedId = 0;
+        }
+
+        this.actor.destroy();
+    },
+
+    _updateUser: function() {
+        if (this._user.is_loaded)
+            this._label.text = this._user.get_real_name();
+        else
+            this._label.text = '';
+
+        this._avatar.update();
+    }
+});
+
+const UnlockDialog = new Lang.Class({
+    Name: 'UnlockDialog',
+    Extends: ModalDialog.ModalDialog,
+
+    _init: function() {
+        this.parent({ shellReactive: true,
+                      styleClass: 'login-dialog' });
+
+        this._userManager = AccountsService.UserManager.get_default();
+        this._userName = GLib.get_user_name();
+        this._user = this._userManager.get_user(this._userName);
+
+        this._greeterClient = new Gdm.Client();
+        this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
+
+        this._userVerifier.connect('reset', Lang.bind(this, this._reset));
+        this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
+        this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
+        this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
+
+        this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
+        this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
+
+        this._userWidget = new UserWidget(this._user);
+        this.contentLayout.add_actor(this._userWidget.actor);
+
+        this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
+                                                vertical: false });
+
+        this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
+        this._promptLayout.add(this._promptLabel,
+                               { expand: false,
+                                 x_fill: true,
+                                 y_fill: true,
+                                 x_align: St.Align.START });
+
+        this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
+                                           can_focus: true });
+        ShellEntry.addContextMenu(this._promptEntry);
+        this.setInitialKeyFocus(this._promptEntry);
+        this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
+
+        this._promptLayout.add(this._promptEntry,
+                               { expand: true,
+                                 x_fill: true,
+                                 y_fill: false,
+                                 x_align: St.Align.START });
+
+        this.contentLayout.add_actor(this._promptLayout);
+
+        // Translators: this message is shown below the password entry field
+        // to indicate the user can swipe their finger instead
+        this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
+                                                        style_class: 'login-dialog-prompt-fingerprint-message' });
+        this._promptFingerprintMessage.hide();
+        this.contentLayout.add_actor(this._promptFingerprintMessage);
+
+        let otherUserLabel = new St.Label({ text: _("Login as another user"),
+                                            style_class: 'login-dialog-not-listed-label' });
+        this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
+                                                can_focus: true,
+                                                child: otherUserLabel,
+                                                reactive: true,
+                                                x_align: St.Align.START,
+                                                x_fill: true });
+        this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
+        this.contentLayout.add(this._otherUserButton,
+                               { x_align: St.Align.START,
+                                 x_fill: false });
+
+        this._okButton = { label: _("Unlock"),
+                           action: Lang.bind(this, this._doUnlock),
+                           default: true };
+        this.setButtons([this._okButton]);
+
+        this._updateOkButton(false);
+        this._reset();
+    },
+
+    _updateOkButton: function(sensitive) {
+        this._okButton.button.reactive = sensitive;
+    },
+
+    _reset: function() {
+        this._userVerifier.begin(this._userName, new Batch.Hold());
+    },
+
+    _onAskQuestion: function(verifier, serviceName, question, passwordChar) {
+        this._promptLabel.text = question;
+
+        this._promptEntry.text = '';
+        this._promptEntry.clutter_text.set_password_char(passwordChar);
+        this._promptEntry.menu.isPassword = passwordChar != '';
+
+        this._currentQuery = serviceName;
+        this._updateOkButton(true);
+    },
+
+    _showFingerprintPrompt: function() {
+        GdmUtil.fadeInActor(this._promptFingerprintMessage);
+    },
+
+    _hideFingerprintPrompt: function() {
+        GdmUtil.fadeOutActor(this._promptFingerprintMessage);
+    },
+
+    _doUnlock: function() {
+        if (!this._currentQuery)
+            return;
+
+        let query = this._currentQuery;
+        this._currentQuery = null;
+
+        this._updateOkButton(false);
+
+        this._userVerifier.answerQuery(query, this._promptEntry.text);
+    },
+
+    _onVerificationComplete: function() {
+        this._userVerifier.clear();
+        this.emit('unlocked');
+    },
+
+    _onVerificationFailed: function() {
+        this._userVerifier.cancel();
+        this.emit('failed');
+    },
+
+    _otherUserClicked: function(button, event) {
+        this._userManager.goto_login_session();
+
+        this._userVerifier.cancel();
+        this.emit('failed');
+    },
+
+    destroy: function() {
+        this._userVerifier.clear();
+        this.parent();
+    },
+
+    cancel: function() {
+        this._userVerifier.cancel(null);
+
+        this.destroy();
+    },
+});